#include <iostream>
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
#include "util.hpp"
using namespace::std;
const std::string src_path="data/input";
const std::string output="data/raw_html/raw.txt";

// 描述文档的结构体
typedef struct DocInfo
{
    std::string title;
    std::string content;
    std::string url;
}DocInfo_t;
// 枚举所有的html文件
bool EnumFile(const std::string& src_path,std::vector<std::string>* files_list)
{   
    namespace fs=boost::filesystem;
    fs::path root_path(src_path);
    if(!fs::exists(root_path))
    {
        std::cerr<<root_path<<" do not exist"<<std::endl;
        return false;
    }
    // 直接构造递归迭代器
    fs::recursive_directory_iterator end;
    for(fs::recursive_directory_iterator iter(root_path);iter!=end;iter++)
    {
        // 判断文件是否为普通文件
        if(!fs::is_regular_file(*iter)) continue;
        if(iter->path().extension() !=".html") continue;
        // std::cout<<iter->path().string()<<std::endl;
        files_list->push_back(iter->path().string());
    }
    return true;
}
// 提取文档标题
bool ParseTitle(const std::string& file,std::string *title)
{
    size_t begin=file.find("<title>");
    if(begin==std::string::npos) 
        return false;
    size_t end=file.find("</title>",begin+1);
    begin+=strlen("<title>");
    if(begin>end)
        return false;
    *title=file.substr(begin,end-begin);
    return true;
}
// 提取文档内容
bool ParseContent(const std::string& file,std::string *content)
{
    // 小型状态机
    enum status{
        LABLE,
        CONTENT
    };
    enum status s=LABLE;
    for(char ch:file)
    {
        switch (s)
        {
        case LABLE:
            if(ch=='>')
            {
                s=CONTENT;
            }
            break;
        case CONTENT:
            if(ch=='<') s=LABLE;
            else{
                if(ch=='\n') ch=' '; // 去掉'\n'
                *content+=ch;
            } 
                
            break;
        default:
            break;
        }
    }
    return true;
}
// 提取文档URL
bool ParseUrl(const std::string& file_path,std::string *url)
{
    std::string url_head="https://www.boost.org/doc/libs/1_87_0/doc/html";
    std::string url_tail=file_path.substr(src_path.size());
    *url=url_head+url_tail;
    return true;
}
// for debug
void ShowDoc(const DocInfo_t& doc)
{
    std::cout<<"title: "<<doc.title<<std::endl;
    std::cout<<"content: "<<doc.content<<std::endl;
    std::cout<<"url: "<<doc.url<<std::endl;
}
// 解析文档
bool ParseHtml(const std::vector<std::string>& files_list,std::vector<DocInfo_t>* results)
{
    for(const auto& file :files_list)
    {
        // 1、先读取文件
        std::string result;
        if(!ns_util::FileUtil::ReadFile(file,&result)) continue;

        DocInfo_t doc; //解析到doc中   
        // 2、提取title
        if(!ParseTitle(result,&doc.title)) continue;
        // 3、提取content
        if(!ParseContent(result,&doc.content)) continue;
        // 4、提取url
        if(!ParseUrl(file,&doc.url)) continue;
        results->push_back(std::move(doc));
        // 调试
        // ShowDoc(doc); break;
    }
    return true;
}
// 把所有html整合为一个大文件
bool SaveHtml(const std::vector<DocInfo_t>& results,const std::string& output)
{
#define SEP '\3'
    std::ofstream out(output,std::ios::out | std::ios::binary);// 二进制方式写入
    if(!out.is_open())
    {
        std::cerr<<"open "<<output<<" error!"<<std::endl;
        return false;
    }
    for(const auto& doc:results)
    {
        std::string serialize_str;
        serialize_str+=doc.title;
        serialize_str+=SEP;
        serialize_str+=doc.content;
        serialize_str+=SEP;        
        serialize_str+=doc.url;
        serialize_str+='\n';
        // "title"\3"content"\3"url"\n …………
        out.write(serialize_str.c_str(),serialize_str.size());
    }
    out.close();
    return true;
}

int main()
{
    std::vector<std::string> files_list;
    //1、枚举所有的html文件，保存到files_list中
    if(!EnumFile(src_path,&files_list))
    {
        std::cerr<<"enum flie name error!"<<std::endl;
        return 1;
    }
    //2、解析所有的html文档，保存到results中
    std::vector<DocInfo_t> results; 
    if(!ParseHtml(files_list,&results)){
        std::cerr<<"parse flie error!"<<std::endl;
        return 2;
    }
    //3、把所有解析后的文档整合在一起,\3为分割符
    if(!SaveHtml(results,output))
    {
        std::cerr<<"save flie error!"<<std::endl;
        return 3;
    }
    
    return 0;
}
